package com.rjkj.medicalwaste

import android.Manifest
import android.annotation.SuppressLint
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.content.*
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.os.IBinder
import android.text.TextUtils
import android.util.Log
import android.view.KeyEvent
import android.view.WindowManager
import android.widget.SimpleExpandableListAdapter
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController
import androidx.navigation.fragment.FragmentNavigator
import com.google.android.material.snackbar.Snackbar
import com.google.gson.Gson
import com.inuker.bluetooth.library.Constants
import com.inuker.bluetooth.library.Constants.*
import com.inuker.bluetooth.library.connect.listener.BleConnectStatusListener
import com.inuker.bluetooth.library.connect.options.BleConnectOptions
import com.inuker.bluetooth.library.connect.response.BleNotifyResponse
import com.inuker.bluetooth.library.receiver.listener.BluetoothBondListener
import com.rjkj.medicalwaste.bean.BlueConnectResult
import com.rjkj.medicalwaste.bean.Decoder04Bean
import com.rjkj.medicalwaste.bean.MedicalWasteType
import com.rjkj.medicalwaste.bean.SettingBean
import com.rjkj.medicalwaste.bluetooth.BluetoothSPP
import com.rjkj.medicalwaste.bluetooth.BluetoothState
import com.rjkj.medicalwaste.database.getDatabase
import com.rjkj.medicalwaste.databinding.ActivityMainBinding
import com.rjkj.medicalwaste.livedatabus.LiveDataBus
import com.rjkj.medicalwaste.ui.blue.BleListFragment
import com.rjkj.medicalwaste.ui.blue.BlueService
import com.rjkj.medicalwaste.ui.collect.CollectMainFragment
import com.rjkj.medicalwaste.ui.collect.CollectScanFragment
import com.rjkj.medicalwaste.ui.first.FirstScanFragment
import com.rjkj.medicalwaste.ui.outbound.OutboundScanFragment
import com.rjkj.medicalwaste.ui.setting.PrintItem
import com.rjkj.medicalwaste.ui.storage.StorageScanFragment
import com.rjkj.medicalwaste.utils.*
import com.rjkj.medicalwaste.viewmodels.BluetoothControlViewModel
import com.rjkj.medicalwaste.viewmodels.MainViewModel
import com.rjkj.medicalwaste.viewmodels.UserViewModel
import com.rjkj.medicalwaste.viewmodels.provider.MainViewModelProvider
import kotlinx.coroutines.*
import okhttp3.internal.waitMillis
import java.io.BufferedReader
import java.io.InputStreamReader
import java.util.*


class MainActivity : AppCompatActivity() {
    private val mainViewModel: MainViewModel by viewModels {
        MainViewModelProvider.provideMainViewModel(this)
    }
    private val bluetoothControlViewModel: BluetoothControlViewModel by viewModels()
    private val userViewModel: UserViewModel by viewModels {
        MainViewModelProvider.provideUserModel(this)
    }
    private val arrays = arrayOf(
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.READ_PHONE_STATE,
        Manifest.permission.CAMERA,
    )
    private var mBlueService: BlueService? = null

    companion object {
        const val SCAN_DATA = "SCAN_DATA"
        const val KEY_DATA = "KEY_DATA"

    }


    private val mBluetoothBondListener: BluetoothBondListener = object : BluetoothBondListener() {
        override fun onBondStateChanged(mac: String, bondState: Int) {
            // bondState = Constants.BOND_NONE, BOND_BONDING, BOND_BONDED
            when (bondState) {
                Constants.BOND_NONE -> Log.e("bondState: ", "BOND_NONE")
                Constants.BOND_BONDING -> Log.e("bondState: ", "BOND_BONDING")
                Constants.BOND_BONDED -> Log.e("bondState: ", "BOND_BONDED")
            }
        }
    }

    abstract class MyServiceConnect(val address: String) : ServiceConnection {

    }


    private fun sendStack() {
        try {
            var line = ""
            var trace = ""
            try {
                val reader = BufferedReader(
                    InputStreamReader(openFileInput("stack.trace"))
                )
                while (reader.readLine().also { line = it } != null) {
                    trace += """
                    $line
                    
                    """.trimIndent()
                }
            } catch (err: Exception) {
                return
            }
            if (trace.length > 5) {
                trace += "SerialNumber:${userViewModel.getSerial()}"
                userViewModel.sendStackInfo(trace)
            }
        } catch (err: Exception) {
            err.printStackTrace()
        }
    }


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
//        // 设置为全屏模式
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
//            val insetsController = window.insetsController
//            insetsController?.hide(WindowInsetsCompat.Type.navigationBars())
//        } else {
//
//        }
        window.setFlags(
            WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN
        )
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { it ->
            //通过的权限
            val grantedList = it.filterValues { it }.mapNotNull { it.key }
            //是否所有权限都通过
            if (grantedList.size == it.size) {
                initScannerNewLoad()
            } else {
                showTip("程序无法使用")
            }
            if (it.containsKey(Manifest.permission.READ_PHONE_STATE)) {
                val imeiDeviceId = DeviceIdentUilts.getIMEIDeviceId(this)
                val serialNum = if (imeiDeviceId.length == 15) {
                    imeiDeviceId
                } else if (UniqueDeviceID.getUniqueId().isNullOrEmpty()) {
                    ""
                } else {
                    UniqueDeviceID.getUniqueId()?.substring(0, 15)
                } ?: ""
                val jsonObject = Gson()
                val string = AppPrefsUtils.getString(BaseConstant.SETTING)
                if (string.isEmpty()) {
                    userViewModel.setting.value!!.serialNum = serialNum
                    val toList =
                        MedicalWasteType.values().filter { it != MedicalWasteType.NUllType }.map {
                            PrintItem(type = it.typeName)
                        }.toList()
                    for (value in toList) {
                        if (value.type == "感染性" || value.type == "损伤性" || value.type == "病理性" || value.type == "药物性" || value.type == "化学性") {
                            value.choose = true
                            value.canClick = false
                        }
                    }
                    userViewModel.setting.value!!.printItemList = toList
                    AppPrefsUtils.putString(
                        BaseConstant.SETTING,
                        jsonObject.toJson(userViewModel.setting.value)
                    )
                } else {
                    val fromJson = jsonObject.fromJson(string, SettingBean::class.java)
                    fromJson.change = false
                    userViewModel.setting.value = fromJson
                }
                if ((userViewModel.setting.value?.infoMode == 0 || userViewModel.setting.value?.infoMode == 2) && it.containsKey(
                        Manifest.permission.ACCESS_FINE_LOCATION
                    )
                ) {
                    initBluetooth()
                }
                val job = loop(serialNum)
                userViewModel.changeUrl.observe(this) {
                    lifecycleScope.launch {
                        if (it) {
                            job.cancelAndJoin()
                            loop(serialNum).start()
                        }
                    }
                }

            } else {
                showTip("程序无法使用")
            }


//            val list = (it - grantedList).map { it.key }
//            //未通过的权限
//            val deniedList =
//                list.filter { ActivityCompat.shouldShowRequestPermissionRationale(this, it) }
//            //拒绝并且点了“不再询问”权限
//            val alwaysDeniedList = list - deniedList
        }.launch(arrays)
        val binding: ActivityMainBinding = DataBindingUtil.setContentView(
            this,
            R.layout.activity_main
        )
        binding.lifecycleOwner = this
        Log.e("TAG", "onCreate: ${UniqueDeviceID.getUniqueId().hashCode()}")
//        sendStack()
    }

    private fun loop(serialNum: String): Job {
        return lifecycleScope.launch(Dispatchers.IO) {
            runCatching {
                while (true) {
                    mainViewModel.requestHistoryInfoLoopData(
                        userViewModel.getUrl(), serialNum, PhoneHelper.packageCode(
                            this@MainActivity
                        ).toString()
                    )
                    val deal = mainViewModel.requestSqlInfoLoopData(
                        userViewModel.getUrl(),
                        serialNum
                    )
                    if (deal != null) {
                        for (value in deal) {
                            try {
                                val database = getDatabase(this@MainActivity)
                                database.runInTransaction {
                                    database.openHelper.writableDatabase.execSQL(value.sqlStatement)
                                }
                                mainViewModel.requestExecSqlResult(
                                    userViewModel.getUrl(),
                                    value.no,
                                    0
                                )
                            } catch (e: Exception) {
                                e.printStackTrace()
                                mainViewModel.requestExecSqlResult(
                                    userViewModel.getUrl(),
                                    value.no,
                                    1
                                )
                            }

                        }
                    }
                    delay(10 * 1000)
                }
            }.onFailure {
                Log.e("onFailure", "轮询发生错误 ")
            }
        }
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        Log.e("onKeyDown", "onKeyDown: ${event?.keyCode}")
        if (event?.keyCode == KeyEvent.KEYCODE_VOLUME_UP || event?.keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
            val navController = findNavController(R.id.fragment)
            val currentDestination = navController.currentDestination
            if (currentDestination is FragmentNavigator.Destination) {
                when (currentDestination.className) {
                    CollectScanFragment::class.java.name -> {
                        LiveDataBus.get().with(KEY_DATA).value = true
                        return true
                    }
                    StorageScanFragment::class.java.name -> {
                        LiveDataBus.get().with(KEY_DATA).value = true
                        return true
                    }
                    OutboundScanFragment::class.java.name -> {
                        LiveDataBus.get().with(KEY_DATA).value = true
                        return true
                    }
                    FirstScanFragment::class.java.name -> {
                        LiveDataBus.get().with(KEY_DATA).value = true
                        return true
                    }
                    CollectMainFragment::class.java.name -> {
                        LiveDataBus.get().with(KEY_DATA).value = true
                        return true
                    }
                }
            }
        }

        return super.onKeyDown(keyCode, event)
    }


    private fun initScannerNewLoad() {
        val filter = IntentFilter("nlscan.action.SCANNER_RESULT")
        filter.addAction("android.intent.ACTION_DECODE_DATA")
        filter.addAction("android.intent.action.scanner.RFID")
        filter.addAction("android.intent.action.SCANRESULT")
        filter.addAction("com.scanner.broadcast")
        registerReceiver(mNewLoadReceiver, filter)
    }


    private val mNewLoadReceiver: BroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            when {
                intent.getStringExtra("SCAN_BARCODE1") != null -> {
                    val scanResult = intent.getStringExtra("SCAN_BARCODE1")
                    if (checkBluetoothMac(scanResult ?: "")) {
                        bluetoothControlViewModel.bluetoothTry.value = BlueConnectResult(scanResult)
                    } else {
                        LiveDataBus.get().with(SCAN_DATA).value = scanResult
                    }

                }
                intent.getStringExtra("barcode_string") != null -> {
                    val scanResult = intent.getStringExtra("barcode_string")
                    if (checkBluetoothMac(scanResult ?: "")) {
                        bluetoothControlViewModel.bluetoothTry.value = BlueConnectResult(scanResult)
                    } else {
                        LiveDataBus.get().with(SCAN_DATA).value = scanResult
                    }
                }
                intent.getStringExtra("data") != null -> {
                    val scanResult = intent.getStringExtra("data")
                    if (checkBluetoothMac(scanResult ?: "")) {
                        bluetoothControlViewModel.bluetoothTry.value = BlueConnectResult(scanResult)
                    } else {
                        LiveDataBus.get().with(SCAN_DATA).value = scanResult
                    }
                }
                intent.getStringExtra("value") != null -> {
                    val scanResult = intent.getStringExtra("value")
                    if (checkBluetoothMac(scanResult ?: "")) {
                        bluetoothControlViewModel.bluetoothTry.value = BlueConnectResult(scanResult)
                    } else {
                        LiveDataBus.get().with(SCAN_DATA).value = scanResult
                    }
                }
            }

        }
    }

    private fun checkBluetoothMac(strMac: String): Boolean {
        val trueMacAddress =
            "^[a-fA-F0-9]{2}+:[a-fA-F0-9]{2}+:[a-fA-F0-9]{2}+:[a-fA-F0-9]{2}+:[a-fA-F0-9]{2}+:[a-fA-F0-9]{2}$"
        return strMac.matches(Regex(trueMacAddress))
    }

    val registerForActivityResult =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            initBluetooth()
        }

    //初始化蓝牙监听，自动连接，数据监听
    @SuppressLint("WrongConstant")
    private fun initBluetooth() {
        ClientManager.client?.registerBluetoothBondListener(mBluetoothBondListener)

        val mBleConnectStatusListener: BleConnectStatusListener =
            object : BleConnectStatusListener() {
                override fun onConnectStatusChanged(mac: String, status: Int) {
                    if (status == STATUS_CONNECTED) {
                        bluetoothControlViewModel.bluetoothType = 2
                        bluetoothControlViewModel.mac = mac
                        AppPrefsUtils.putString(
                            BaseConstant.BLUETOOTH_MAC,
                            mac
                        )
                        showTip("蓝牙连接成功")
                        dealBleData(mac)
                    } else if (status == STATUS_DISCONNECTED) {
                        showTip("蓝牙连接已断开")
                        Log.e("TAG", "initBluetooth: 重新连接蓝牙")
                        bluetoothControlViewModel.bluetoothTry.value =
                            BlueConnectResult(
                                mac,
                                BluetoothDevice.DEVICE_TYPE_LE
                            )
                        bluetoothControlViewModel.bluetoothType = 0
                        bluetoothControlViewModel.mac = ""
                    }
                }
            }
        val bt = BlueManager.instance.blue
        if (!bt.isBluetoothAvailable) {
            return
        }
        if (!bt.isBluetoothEnabled) {
            val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
            registerForActivityResult.launch(intent)
            return
        }

        bluetoothControlViewModel.bluetoothTry.observe(this) {
            if (it != null) {
                Log.e("bluetoothTry", "initBluetooth: ${it.toString()}")
            }
            if (userViewModel.setting.value?.infoMode == 0 || userViewModel.setting.value?.infoMode == 2) {//PDA模式自动连接蓝牙
                if (it?.mac != null && it.mac.isNotEmpty()) {
                    val options = BleConnectOptions.Builder()
                        .setConnectRetry(3)
                        .setConnectTimeout(20000)
                        .setServiceDiscoverRetry(3)
                        .setServiceDiscoverTimeout(10000)
                        .build()
                    when (it.type) {
//                        99 -> {
//                            val gattServiceIntent = Intent(this, BlueService::class.java)
//                            val mServiceConnection: ServiceConnection =
//                                object : MyServiceConnect(it.mac) {
//                                    override fun onServiceConnected(
//                                        componentName: ComponentName,
//                                        service: IBinder
//                                    ) {
//                                        mBlueService = (service as BlueService.LocalBinder).service
//                                        println("isconnect")
//                                        if (!mBlueService!!.initialize()) {
////                                            Log.e(TAG, "Unable to initialize Bluetooth")
//                                            finish()
//                                        }
//                                        mBlueService!!.connect(address)
//                                    }
//
//                                    override fun onServiceDisconnected(componentName: ComponentName) {
//                                        mBlueService = null
//                                        println("disconnect")
//                                    }
//                                }
//                            this.bindService(gattServiceIntent, mServiceConnection, 1)
//                            this.registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter())
//                            if (mBlueService != null) {
//                                val result = mBlueService!!.connect(it.mac)
//                                Log.d("mBlueService", "Connect request result=$result")
//                            }
//                        }
                        BluetoothDevice.DEVICE_TYPE_UNKNOWN -> {
                            Log.e("TAG", "DEVICE_TYPE_UNKNOWN: ")
                        }
                        BluetoothDevice.DEVICE_TYPE_CLASSIC -> {
                            BlueManager.instance.blue.apply {
                                Log.e("TAG", "initBluetooth: $connectedDeviceAddress")
                                if (serviceState == BluetoothState.STATE_CONNECTED) {
                                    Log.e("TAG", "STATE_CONNECTED:")
                                    return@observe
                                }
                                connect(it.mac)
                            }

                        }
                        BluetoothDevice.DEVICE_TYPE_LE -> {
                            ClientManager.client?.registerConnectStatusListener(
                                it.mac,
                                mBleConnectStatusListener
                            )
                            ClientManager.client?.connect(
                                it.mac,
                                options
                            ) { code, _ ->
                                if (code == REQUEST_FAILED) {
                                    lifecycleScope.launch {
                                        delay(2000)
                                        Log.e("TAG", "initBluetooth: 重新连接蓝牙")
                                        bluetoothControlViewModel.bluetoothTry.value =
                                            BlueConnectResult(
                                                it.mac,
                                                BluetoothDevice.DEVICE_TYPE_LE
                                            )
                                    }
                                }
                            }

                        }
                        BluetoothDevice.DEVICE_TYPE_DUAL -> {
                            ClientManager.client?.connect(it.mac, options) { code, _ ->
                                if (code == 0) {
                                    showTip("连接成功")
                                    bluetoothControlViewModel.bluetoothType = 2
                                    bluetoothControlViewModel.mac = it.mac
                                    AppPrefsUtils.putString(
                                        BaseConstant.BLUETOOTH_MAC,
                                        it.mac
                                    )
                                }
                            }
                        }
                    }

                }
            }
        }
        bt.setOnDataReceivedListener { data, _ ->
            val dataStr = SerializeUtil.byteArrayToHexString(data)
            if (BlueDeviceHelper.checkDecoderStr04(dataStr)) {
                Log.e("decoder04", "onDataReceived: $dataStr")
                bluetoothControlViewModel.decoder04Bean.value =
                    BlueDeviceHelper.readDecoder04Message(
                        dataStr
                    )
            } else if (BlueDeviceHelper.checkDecoderStr03(dataStr)) {
                Log.e("decoder03", "onDataReceived: $dataStr")
                bluetoothControlViewModel.decoder03Bean.value =
                    BlueDeviceHelper.readDecoder03Message(
                        dataStr
                    )
            }
        }


        //该回调处理断开 失败等监听
        bt.setBluetoothConnectionListener(object : BluetoothSPP.BluetoothConnectionListener {
            override fun onDeviceConnected(name: String?, address: String?) {
                showTip("蓝牙设备已连接")
                bluetoothControlViewModel.bluetoothType = 1
                if (address != null) {
                    bluetoothControlViewModel.mac = address
                }
                bluetoothControlViewModel.bluetoothSwitch.value = true
                AppPrefsUtils.putString(BaseConstant.BLUETOOTH_MAC, address ?: "")
            }

            override fun onDeviceDisconnected() {
                val mac = bluetoothControlViewModel.mac
                lifecycleScope.launch {
                    delay(2000)
                    bluetoothControlViewModel.bluetoothTry.value = BlueConnectResult(mac)
                }
                bluetoothControlViewModel.bluetoothSwitch.value = false
                bluetoothControlViewModel.bluetoothType = 0
                bluetoothControlViewModel.mac = ""
                showTip("蓝牙设备连接已断开")
            }

            override fun onDeviceConnectionFailed() {
                val mac = bluetoothControlViewModel.mac
                lifecycleScope.launch {
                    delay(2000)
                    bluetoothControlViewModel.bluetoothTry.value = BlueConnectResult(mac)
                }

                bluetoothControlViewModel.bluetoothSwitch.value = false
                bluetoothControlViewModel.bluetoothType = 0
//                bluetoothControlViewModel.mac = ""
                showTip("蓝牙设备连接失败")
            }

        })

        //自动连接的监听
        bt.setAutoConnectionListener(object : BluetoothSPP.AutoConnectionListener {
            override fun onAutoConnectionStarted() {
            }

            override fun onNewConnection(name: String?, address: String?) {
            }

        })

        //状态监听
        bt.setBluetoothStateListener { state ->
            when (state) {
                BluetoothState.STATE_NONE -> showTip2("STATE_NONE")
                BluetoothState.STATE_LISTEN -> showTip2("STATE_LISTEN")
                BluetoothState.STATE_CONNECTING -> showTip2("STATE_CONNECTING")
                BluetoothState.STATE_CONNECTED -> showTip2("STATE_CONNECTED")
                BluetoothState.STATE_NULL -> showTip2("STATE_NULL")
            }
        }
        if (bt.isBluetoothEnabled) {
            if (!bt.isServiceAvailable) {
                bt.setupService()
                bt.startService(BluetoothState.DEVICE_OTHER)
            }
        }

    }

    private fun showTip2(s: String) {
        Log.e("BluetoothState", ": $s")
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(mNewLoadReceiver)
        ClientManager.client?.unregisterBluetoothBondListener(mBluetoothBondListener)
        val bt = BlueManager.instance.blue
        bt.stopService()
        bt.disconnect()
    }

    fun showTip(message: String) {
        if (TextUtils.isEmpty(message)) {
            return
        }
        Snackbar.make(findViewById(R.id.main_content), message, Snackbar.LENGTH_LONG).apply {
            view.setBackgroundColor(
                ContextCompat.getColor(
                    this@MainActivity,
                    R.color.black_grey
                )
            )
            view.findViewById<TextView>(com.google.android.material.R.id.snackbar_text).also {
                it.textSize = 28f
                it.setTextColor(Color.WHITE)
            }
        }.show()
    }

    fun dealBleData(mac: String) {

        val UUID_SERVER = "0000ffe0-0000-1000-8000-00805f9b34fb"
        val UUID_STRING = "0000ffe1-0000-1000-8000-00805f9b34fb"
        ClientManager.client?.notify(
            mac,
            UUID.fromString(UUID_SERVER),
            UUID.fromString(UUID_STRING),
            object : BleNotifyResponse {
                override fun onNotify(
                    service: UUID?,
                    character: UUID?,
                    value: ByteArray?
                ) {
                    // 打开通知后，设备发过来的数据将在这里出现
                    val s = SerializeUtil.byteArrayToHexString(value)
                    val dataStr =
                        SerializeUtil.hexStr2Str(s)
//                    Log.e("TAG", "onNotify: $dataStr+${dataStr.length}")
                    if (dataStr.length > 1 && dataStr.substring(
                            0,
                            2
                        ) == "UN" && dataStr.length == 18
                    ) {
                        val weightStrKG =
                            dataStr.substring(6).trim { it <= ' ' }
                        val weightFinal = weightStrKG.substring(
                            0,
                            weightStrKG.length - 2
                        )
                        var weightFinal2 = weightFinal
                        if (weightFinal.contains("+")) {
                            weightFinal2 = weightFinal.replace("+", "")
                                .trim { it <= ' ' }
                        } else if (weightFinal.contains("-")) {
                            weightFinal2 =
                                "-" + weightFinal.replace("-", "")
                                    .trim { it <= ' ' }
                        }
                        bluetoothControlViewModel.decoder04Bean.value =
                            Decoder04Bean().apply {
                                weight = weightFinal2
                            }

                    }


                }

                override fun onResponse(code: Int) {

                }
            })

        AppPrefsUtils.putString(
            BaseConstant.BLUETOOTH_MAC,
            mac
        )
    }
}